#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <unistd.h>
#include "proto.h"

enum
{
	FSM_SEND = 1,
	FSM_RECV,
	FSM_OUT,
	FSM_EX,
	FSM_T
};

struct fsm_st
{
	int state;
	struct path_st path;
	union recv_data recvData;
	int pos;
	char *errstr;
};

void driver(struct fsm_st *pathData, int msgid)
{
	int ret;
	switch (pathData->state)
	{
		case FSM_SEND:
			pathData->path.type = MSG_PATH;
			fgets(pathData->path.path, PATHSIZE, stdin);
			if (msgsnd(msgid, &pathData->path, sizeof(pathData->path), 0) < 0)
			{
				pathData->state = FSM_EX;
				pathData->errstr = "msgsnd()";
			}
			else
				pathData->state = FSM_RECV;
			break;
		case FSM_RECV:
			if (msgrcv(msgid, &pathData->recvData, sizeof(pathData->recvData), 0, 0) < 0)
			{
				pathData->state = FSM_EX;
				pathData->errstr = "msgrcv()";
			}
			else
			{
				if (pathData->recvData.type == MSG_DATA)
					pathData->state = FSM_OUT;
				else
					pathData->state = FSM_T;
				pathData->pos = 0;
			}
			break;
		case FSM_OUT:
			ret = write(1, pathData->recvData.data.data + pathData->pos, pathData->recvData.data.datalen);
			if (ret < 0)
			{
				pathData->state = FSM_EX;
				pathData->errstr = "write()";
			}
			else
			{
				pathData->recvData.data.datalen -= ret;
				pathData->pos += ret;
				if (pathData->recvData.data.datalen == 0)
					pathData->state = FSM_RECV;
				else
					pathData->state = FSM_OUT;
			}
			break;
		case FSM_EX:
			perror(pathData->errstr);
			pathData->state = FSM_T;
			break;
		case FSM_T:
			/*do sth*/
			break;	
		default:
			abort();
			break;
	}
}

int main(int argc, char **argv)
{
   
	key_t key;
	int msgid;
	struct fsm_st pathData;	

	key = ftok(KEYPATH, PROJID);	
	if (key < 0)
	{
		perror("ftok()");	
		exit(1);
	}
	
	msgid = msgget(key, 0);
	if (msgid < 0)
	{
		perror("msgget()");
		exit(1);
	}

	pathData.state = FSM_SEND;

	while (pathData.state != FSM_OUT)
	{
		driver(&pathData, msgid);
	}
	
	msgctl(msgid, IPC_RMID, NULL);

	exit(0);
}
